#!/usr/bin/perl
#执行前提：PATH中包含$GRID_HOME/bin:$ORACLE_HOME/bin, LD_LIBRARY_PATH包含$GRID_HOME/lib:$ORACLE_HOME/bin
use FindBin;
use lib "$FindBin::Bin/lib";
use lib "$FindBin::Bin/lib/perl-lib/lib/perl5";

use strict;
use Cwd;
use IO::File;
use File::Copy;
use Socket;
use Getopt::Long;
use SqlplusExec;
use AutoExecUtils;

sub usage {
    my $pname = $FindBin::Script;

    print("$pname --GRID_USER <GRID_USER> --ORACLE_USER <ORACLE_USER> --DB_UNIQUE_NAME <DB_UNIQUE_NAME>\n");
    exit(1);
}

sub getCrsHome {
    my ( $osUser, $ORACLE_HOME ) = @_;

    print("Try to get crs home directory...\n");
    my $envLine = 'LANG=en_US.UTF-8';

    my $gridHome = '';
    my $cmdFile  = "$ORACLE_HOME/srvm/admin/getcrshome";
    if ( -e $cmdFile ) {
        $gridHome = `su - '$osUser' -c '$cmdFile'`;
        if ( $? == 0 ) {
            $gridHome =~ s/^\s*|\s*$//g;
        }
    }
    print("Oracle crs home:$gridHome\n");
    return $gridHome;
}

sub getDBMajorVersion {
    my ($osUser) = @_;
    print("Try to get db major version...\n");
    my $majorVersion = `su - '$osUser' -c 'oraversion -majorVersion'`;
    if ( $? == 0 ) {
        $majorVersion =~ s/^\s*|\s*$//g;
    }
    else {
        undef($majorVersion);
    }
    print("DB major version:$majorVersion.\n");
    return $majorVersion;
}

sub getConfig {
    my ( $osUser, $sid ) = @_;
    my $sqlplus = SqlplusExec->new( osUser => $osUser, sid => $sid );

    my $rows;

    #SELECT SEQUENCE# FROM V$THREAD where THREAD#='1'
    $rows = $sqlplus->query(
        sql     => q{SELECT SEQUENCE# as SEQUENCE FROM V$THREAD where THREAD#='1'},
        verbose => 1
    );
    my $SEQUENCE;
    if ( defined($rows) ) {
        $SEQUENCE = $$rows[0]->{SEQUENCE};
    }

    #SELECT COUNT(1) AS TEMP_FILES_COUNT FROM DBA_TEMP_FILES;
    $rows = $sqlplus->query(
        sql     => q{SELECT COUNT(1) AS TEMP_FILES_COUNT FROM DBA_TEMP_FILES},
        verbose => 1
    );
    my $TEMP_FILES_COUNT;
    if ( defined($rows) ) {
        $TEMP_FILES_COUNT = $$rows[0]->{TEMP_FILES_COUNT};
    }

    return ( $SEQUENCE, $TEMP_FILES_COUNT );
}

sub getDBParameters {
    my ( $osUser, $sid ) = @_;
    my $sqlplus = SqlplusExec->new( osUser => $osUser, sid => $sid );

    my $rows;
    print("Try to get database parameters...\n");

    #SHOW PARAMETER NAME
    $rows = $sqlplus->query(
        sql     => q{select name,value from v$parameter;},
        verbose => 0
    );

    my $dbParameters = {};
    if ( defined($rows) ) {
        foreach my $row (@$rows) {
            $dbParameters->{ $row->{NAME} } = $row->{VALUE};
        }
        print("Get database parameters finished.\n");
    }
    else {
        print("WARN: Get database parameters failed.\n");
    }
    return $dbParameters;
}

sub getDBInstances {
    my ( $osUser, $dbUniqueName, $localNodeName ) = @_;

    print("Try to get db instances...\n");

    my $envLine = 'LANG=en_US.UTF-8';

    # [oracle@myrac1 ~]$ srvctl status database -d mydb_primary
    # Instance mydb1 is not running on node myrac1
    # Instance mydb2 is not running on node myrac2
    # Instance mydb3 is not running on node myrac3
    my $dbStatusTxt = `su - '$osUser' -c "$envLine srvctl status database -d $dbUniqueName"`;

    my $localInsName;
    my $instances = {};
    foreach my $line ( split( /\n/, $dbStatusTxt ) ) {
        if ( $line =~ /Instance\s+(\w+).*?\snode\s+(\w+)/ ) {
            my $insName  = $1;
            my $nodeName = $2;
            $instances->{$insName} = { hostName => $nodeName };
            if ( $nodeName eq $localNodeName ) {
                $localInsName = $insName;
            }
        }
    }

    print( "Cluster database nodes:" . join( ',', keys(%$instances) ) . "\n" );
    return ( $localInsName, $instances );
}

sub getRacDBInfo {
    my ( $osUser, $dbUniqueName ) = @_;

    print("Try to get rac db info...\n");
    my $racInfo = {};
    my $envLine = 'LANG=en_US.UTF-8';

    if ( not defined($dbUniqueName) ) {
        $dbUniqueName = `su - '$osUser' -c "$envLine srvctl config database"`;
        $dbUniqueName =~ s/^\s*|\s*$//g;
    }

    #srvctl config database -d mydb_primary
    # [oracle@myrac1 ~]$ srvctl config database -d mydb_primary
    # Database unique name: mydb_primary
    # Database name: mydb
    # Oracle home: /db/oracle/app/oracle/product/19.3.0/db
    # Oracle user: oracle
    # Spfile: +DATA/MYDB_PRIMARY/PARAMETERFILE/spfile.275.1119294627
    # Password file: +DATA/MYDB_PRIMARY/PASSWORD/pwdmydb_primary.256.1119292157
    # Domain:
    # Start options: open
    # Stop options: immediate
    # Database role: PRIMARY
    # Management policy: AUTOMATIC
    # Server pools:
    # Disk Groups: ARCH,DATA
    # Mount point paths:
    # Services:
    # Type: RAC
    # Start concurrency:
    # Stop concurrency:
    # OSDBA group: dba
    # OSOPER group: oper
    # Database instances: mydb1,mydb2,mydb3
    # Configured nodes: myrac1,myrac2,myrac3
    # CSS critical: no
    # CPU count: 0
    # Memory target: 0
    # Maximum memory: 0
    # Default network number for database services:
    # Database is administrator managed
    my $dbConf    = {};
    my $dbConfTxt = `su - '$osUser' -c "$envLine srvctl config database -d $dbUniqueName"`;
    foreach my $dbConfLine ( split( /\n/, $dbConfTxt ) ) {
        if ( $dbConfLine =~ /^\s*([^:]+):\s*(.*?)$/ ) {
            $dbConf->{$1} = $2;
        }
        elsif ( $dbConfLine =~ /policy managed/ ) {
            $dbConf->{'Policy Managed'} = 1;
        }
    }

    $racInfo->{DB_UNIQUE_NAME} = $dbUniqueName;
    $racInfo->{DB_NAME}        = $dbConf->{'Database name'};
    $racInfo->{ORACLE_HOME}    = $dbConf->{'Oracle home'};
    $racInfo->{SPFILE}         = $dbConf->{'Spfile'};
    $racInfo->{PASSWORD_FILE}  = $dbConf->{'Password file'};
    $racInfo->{DATABASE_ROLE}  = $dbConf->{'DATABASE_ROLE'};
    $racInfo->{DISK_GROUPS}    = $dbConf->{'Disk Groups'};
    $racInfo->{SERVER_POOLS}   = $dbConf->{'Server pools'};
    $racInfo->{TYPE}           = $dbConf->{'Type'};
    $racInfo->{INSTANCES}      = $dbConf->{'Database instances'};
    $racInfo->{NODES}          = $dbConf->{'Configured nodes'};

    print("Get rac database config finished.\n");
    return $racInfo;
}

sub getCrsInfo {
    my ($osUser) = @_;

    print("Try to get cluster nodes info...\n");

    my $envLine = 'LANG=en_US.UTF-8';

    my $crsInfo = {};

    #cemutlo -n
    my $crsName = `su - '$osUser' -c "$envLine cemutlo -n"`;
    $crsName =~ s/^\s*|\s*$//g;
    $crsInfo->{NAME} = $crsName;

    my $localNodeName = `su - '$osUser' -c '$envLine olsnodes -l'`;
    $localNodeName =~ s/^\s*|\s*$//g;
    $crsInfo->{LOCAL_NODE_NAME} = $localNodeName;

    my $nodeNames = `su - '$osUser' -c '$envLine olsnodes'`;
    $nodeNames =~ s/^\s*|\s*$//g;
    $crsInfo->{ALL_NODE_NAMES} = $nodeNames;

    my $nodesVip = {};
    foreach my $nodeName ( split( /\n/, $nodeNames ) ) {

        #srvctl status vip -n myrac1
        # [oracle@myrac1 ~]$ srvctl status vip -n myrac1
        # VIP 192.168.0.112 is enabled
        # VIP 192.168.0.112 is running on node: myrac1
        my $nodeVipTxt = `su - '$osUser' -c '$envLine srvctl status vip -n $nodeName'`;
        if ( $nodeVipTxt =~ /([\d\.]{7,15})/ ) {
            $nodesVip->{$nodeName} = $1;
        }
    }
    $crsInfo->{NODES_VIP} = $nodesVip;

    print("Get oracle cluster node names ad vips finished.\n");
    return $crsInfo;
}

sub getUserEnv {
    my ( $GRID_USER, $ORACLE_USER ) = @_;

    print("Try to get user environment...\n");

    my $env        = {};
    my $gridEnvTxt = `su - '$GRID_USER' -c "env | grep ORACLE_"`;
    foreach my $envLine ( split( "\n", $gridEnvTxt ) ) {
        if ( $envLine =~ /(\w+)=(.*)$/ ) {
            my $name = $1;
            my $val  = $2;

            if ( $name eq 'ORACLE_HOME' ) {
                $env->{GRID_HOME} = $val;
                my $oraInstFh = IO::File->new("<$val/oraInst.loc");
                if ( defined($oraInstFh) ) {
                    while ( my $line = $oraInstFh->getline() ) {

                        #inventory_loc=/db/oracle/app/oraInventory
                        if ( $line =~ /inventory_loc=\s*(.*?)\s*$/ ) {
                            $env->{INVENTORY_DIR} = $1;
                        }
                    }
                    $oraInstFh->close();
                }
            }
            elsif ( $name eq 'ORACLE_BASE' ) {
                $env->{GRID_BASE} = $val;
            }
        }
    }

    my $oraEnvTxt = `su - '$ORACLE_USER' -c "env | grep ORACLE_"`;
    foreach my $envLine ( split( "\n", $oraEnvTxt ) ) {
        if ( $envLine =~ /(\w+)=(.*)$/ ) {
            my $name = $1;
            my $val  = $2;

            if ( $name eq 'ORACLE_HOME' ) {
                $env->{ORACLE_HOME} = $val;
            }
            elsif ( $name eq 'ORACLE_BASE' ) {
                $env->{ORACLE_BASE} = $val;
            }
        }
    }

    print("Get user environment complete.\n");

    return $env;
}

sub getScanInfo {
    my ($osUser) = @_;

    print("Try to get oracle cluster scan ip...\n");

    my $envLine = 'LANG=en_US.UTF-8';

    # [oracle@myrac1 ~]$ srvctl config scan
    # SCAN name: myrac-scan, Network: 1
    # Subnet IPv4: 192.168.0.0/255.255.254.0/ens192, static
    # Subnet IPv6:
    # SCAN 1 IPv4 VIP: 192.168.0.110
    # SCAN VIP is enabled.
    my @scanVips   = ();
    my $scanVipTxt = `su - '$osUser' -c "$envLine srvctl config scan"`;

    #print("DEBUG:$scanVipTxt");
    while ( $scanVipTxt =~ /VIP:\s*([\d\.]{7,15})/isg ) {
        push( @scanVips, $1 );
    }

    print( "Get oracle cluster scan ip:" . join( ',', @scanVips ) . "\n" );
    return \@scanVips;
}

sub getLsnrAddrs {
    my ($osUser) = @_;

    print("Try to get listener info...\n");
    my $envLine = 'LANG=en_US.UTF-8';

    # [oracle@myrac1 ~]$ lsnrctl status|grep DESCRIPTION
    # (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=LISTENER)))
    # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.111)(PORT=1521)))
    # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.112)(PORT=1521)))
    # [oracle@myrac1 ~]$

    my @addrs      = ();
    my $scanVipTxt = `su - '$osUser' -c "$envLine lsnrctl status LISTENER"`;

    while ( $scanVipTxt =~ /\(HOST\s*=\s*([^\)]+)\s*\).?\(PORT\s*=\s*(\d+)\)/isg ) {
        my $host = $1;
        my $port = $2;
        if ( $scanVipTxt =~ /DESCRIPTION/ ) {
            if ( $host !~ /^[\d\.]+$/ ) {
                my $packedIp = gethostbyname($host);
                if ( defined($packedIp) ) {
                    $host = inet_ntoa($packedIp);
                }
                else {
                    print("WARN: Can not determine hsot:$host ip.\n");
                    next;
                }
            }
            push( @addrs, { host => $host, port => $port } );
        }
    }

    my @sortedAddrs = sort { $a->{host} . ':' . $a->{port} <=> $b->{host} . ':' . $b->{port} } (@addrs);

    print("Get listener config finished.\n");
    return \@sortedAddrs;
}

sub getNodesIpInfo {
    my ( $localNodeName, $nodeNames ) = @_;

    print("Try to get cluster nodes ip...\n");

    my $nodesIpInfo = {};

    my $gridNodeIpTxt      = '';
    my $gridNodeIpInfo     = {};
    my @allGridNodesInfo   = ();
    my @otherGridNodesInfo = ();
    my @thisNodesInfo      = ();

    my @nodeNamesArray = sort ( split( "\n", $nodeNames ) );
    my $otherNodeNames = '';
    foreach my $gridNode (@nodeNamesArray) {
        my $ipAddr;
        my $packedIp = gethostbyname($gridNode);
        if ( defined($packedIp) ) {
            $ipAddr        = inet_ntoa($packedIp);
            $gridNodeIpTxt = $gridNodeIpTxt . $gridNode . " " . $ipAddr . "\n";
            push( @allGridNodesInfo, { 'ip' => $ipAddr } );
            $gridNodeIpInfo->{$gridNode} = $ipAddr;
        }
        else {
            print("WARN: Can not determine ip for node:$gridNode.\n");
            next;
        }
        $gridNode =~ s/^\s*|\s*$//g;
        if ( $gridNode eq $localNodeName ) {
            push( @thisNodesInfo, { 'ip' => $ipAddr } );
        }
        else {
            $otherNodeNames = $otherNodeNames . $gridNode . "\n";
            push( @otherGridNodesInfo, { 'ip' => $ipAddr } );
        }
    }

    $nodesIpInfo->{allGridNodesInfo}   = \@allGridNodesInfo;
    $nodesIpInfo->{otherGridNodesInfo} = \@otherGridNodesInfo;
    $nodesIpInfo->{thisNodesInfo}      = \@thisNodesInfo;
    $nodesIpInfo->{gridNodeIpInfo}     = $gridNodeIpInfo;
    $nodesIpInfo->{gridNodeIpTxt}      = $gridNodeIpTxt;

    if ( scalar(@otherGridNodesInfo) > 0 ) {
        $nodesIpInfo->{operNodeInfo} = [ $otherGridNodesInfo[0] ];
    }

    $otherNodeNames =~ s/^\s*|\s*$//g;
    $nodesIpInfo->{otherNodeNames} = $otherNodeNames;

    print("Get cluster nodes ip complete.\n");

    return $nodesIpInfo;
}

sub main {
    AutoExecUtils::setEnv();
    my $opts = {};
    GetOptions(
        $opts, qw{
            GRID_USER=s
            ORACLE_USER=s
            DB_NAME=s
            DB_UNIQUE_NAME=s
            ONLY_NODES=s
        }
    );

    my $hasOptErr    = 0;
    my $dbName       = $opts->{DB_NAME};
    my $dbUniqueName = $opts->{DB_UNIQUE_NAME};
    my $ORACLE_USER  = $opts->{ORACLE_USER};
    my $GRID_USER    = $opts->{GRID_USER};
    my $onlyNodes    = $opts->{ONLY_NODES};

    if ( not defined($ORACLE_USER) or $ORACLE_USER eq '' ) {
        $hasOptErr = 1;
        print("ERROR: Must defined ORACLE_USER by option --ORACLE_USER.\n");
    }
    if ( not defined($GRID_USER) or $GRID_USER eq '' ) {
        $hasOptErr = 1;
        print("ERROR: Must defined GRID_USER by option --GRID_USER.\n");
    }
    if ( $hasOptErr == 1 ) {
        usage();
    }

    if ( not defined($onlyNodes) or $onlyNodes eq '' ) {
        $onlyNodes = 0;
    }
    else {
        $onlyNodes = int($onlyNodes);
    }

    my $hasError = 0;

    my $out = {};

    my $userEnv   = getUserEnv( $GRID_USER, $ORACLE_USER );
    my $GRID_HOME = $userEnv->{GRID_HOME};
    $out->{GRID_HOME}     = $GRID_HOME;
    $out->{GRID_BASE}     = $userEnv->{GRID_BASE};
    $out->{INVENTORY_DIR} = $userEnv->{INVENTORY_DIR};

    my $ORACLE_HOME = $userEnv->{ORACLE_HOME};
    $out->{ORACLE_HOME} = $ORACLE_HOME;
    $out->{ORACLE_BASE} = $userEnv->{ORACLE_BASE};

    my $gridHome = getCrsHome( $ORACLE_USER, $ORACLE_HOME );
    $out->{crsHome} = $gridHome;

    my $majorVersion = getDBMajorVersion($ORACLE_USER);
    $out->{majorVersion} = $majorVersion;

    if ( ( defined($GRID_USER) and $GRID_USER ne $ORACLE_USER ) or ( defined($gridHome) and $gridHome ne '' ) ) {
        my $racInfo = getRacDBInfo( $GRID_USER, $dbUniqueName );
        $dbName = $racInfo->{DB_NAME};
        $out->{dbUniqueName} = $dbUniqueName;

        my $crsInfo       = getCrsInfo($GRID_USER);
        my $localNodeName = $crsInfo->{LOCAL_NODE_NAME};
        $out->{nodeName}     = $localNodeName;
        $out->{crsName}      = $crsInfo->{NAME};
        $out->{allNodeNames} = $crsInfo->{ALL_NODE_NAMES};

        my $nodesIpInfo = getNodesIpInfo( $localNodeName, $crsInfo->{ALL_NODE_NAMES} );
        my $localIp     = ${ $nodesIpInfo->{thisNodesInfo} }[0]->{ip};

        $out->{allGridNodesInfo}   = $nodesIpInfo->{allGridNodesInfo};
        $out->{otherGridNodesInfo} = $nodesIpInfo->{otherGridNodesInfo};
        $out->{thisNodesInfo}      = $nodesIpInfo->{thisNodesInfo};
        $out->{gridNodeIpInfo}     = $nodesIpInfo->{gridNodeIpInfo};
        $out->{gridNodeIpTxt}      = $nodesIpInfo->{gridNodeIpTxt};
        $out->{operNodeInfo}       = $nodesIpInfo->{operNodeInfo};
        $out->{otherNodeNames}     = $nodesIpInfo->{otherNodeNames};

        if ( $onlyNodes == 0 ) {
            my $dbInfo = getDBParameters($ORACLE_USER);
            $out->{dbParameters} = $dbInfo;
            $out->{spfilePath}   = $dbInfo->{spfile};

            if ( not defined($dbName) or $dbName eq '' ) {
                $dbName = $dbInfo->{db_name};
            }
            $out->{dbName} = $dbName;

            my $gridNodeIpInfo   = $nodesIpInfo->{gridNodeIpInfo};
            my $nodesVipMap      = $crsInfo->{NODES_VIP};
            my $dbInstancesIpTxt = '';
            my ( $localInsName, $dbInstancesIpInfo ) = getDBInstances( $GRID_USER, $dbUniqueName, $localNodeName );
            foreach my $insName ( keys(%$dbInstancesIpInfo) ) {
                my $insInfo  = $dbInstancesIpInfo->{$insName};
                my $nodeName = $insInfo->{hostName};
                $insInfo->{ip}    = $gridNodeIpInfo->{$nodeName};
                $insInfo->{vip}   = $nodesVipMap->{$nodeName};
                $dbInstancesIpTxt = $dbInstancesIpTxt . "\n" . "$insName $nodeName" . $insInfo->{hostname} . ' ' . $insInfo->{ip} . ' ' . $insInfo->{vip};
            }
            $out->{dbInstancesIpInfo} = $dbInstancesIpInfo;
            $out->{dbInstancesIpTxt}  = $dbInstancesIpTxt;

            if ( not defined($localInsName) or $localInsName eq '' ) {
                my $oraSid = `su - '$ORACLE_USER' -c "echo \$ORACLE_SID"`;
                $oraSid =~ s/^\s*|\s*$//g;
                $localInsName = $oraSid;
            }
            $out->{instanceName} = $localInsName;

            my $lsnAddrs = getLsnrAddrs($GRID_USER);
            my $port     = 1521;
            if ( scalar(@$lsnAddrs) > 0 ) {
                $port = $$lsnAddrs[0]->{port};

                # tnstestdbdg =
                # (DESCRIPTION =
                #     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.43)(PORT = 1522))
                #     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.44)(PORT = 1522))
                #     (CONNECT_DATA =
                #     (SERVER = DEDICATED)
                #     (SERVICE_NAME = testdbdg)
                #     )
                # )
                my $uniqDbTnsConf = "$dbUniqueName = \n";
                $uniqDbTnsConf = $uniqDbTnsConf . "  (DESCRIPTION =\n";

                my $dbTnsConf = "$dbName = \n";
                $dbTnsConf = $dbTnsConf . "  (DESCRIPTION =\n";
                foreach my $insName ( keys(%$dbInstancesIpInfo) ) {
                    my $insInfo  = $dbInstancesIpInfo->{$insName};
                    my $nodeName = $insInfo->{hostName};
                    my $vip      = $insInfo->{vip};
                    my $ip       = $insInfo->{ip};
                    if ( defined($vip) ) {
                        $uniqDbTnsConf = $uniqDbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $vip)(PORT = $port))\n";
                        $dbTnsConf     = $dbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $vip)(PORT = $port))\n";
                    }
                    elsif ( defined($ip) ) {
                        $uniqDbTnsConf = $uniqDbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $ip)(PORT = $port))\n";
                        $dbTnsConf     = $dbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $ip)(PORT = $port))\n";
                    }
                }
                if ( $majorVersion >= 10 ) {

                    #Oracle版本大于等于10，增加了UR=A的设定，让tns可以再实例监听处于BLOCKED状态仍然可以进行管理连接
                    $uniqDbTnsConf = $uniqDbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbUniqueName) (UR=A))\n)\n";
                }
                else {
                    $uniqDbTnsConf = $uniqDbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbUniqueName))\n)\n";
                }

                $dbTnsConf            = $dbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbName))\n)\n";
                $out->{uniqDbTnsConf} = $uniqDbTnsConf;
                $out->{dbTnsConf}     = $dbTnsConf;

                my $racScanTnsConf = "$dbName = \n";
                $racScanTnsConf = $racScanTnsConf . "  (DESCRIPTION =\n";
                my $scanVips = getScanInfo($ORACLE_USER);
                foreach my $scanVip (@$scanVips) {
                    $racScanTnsConf = $racScanTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $scanVip)(PORT = $port))\n";
                }
                $racScanTnsConf = $racScanTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbName))\n)\n";
                $out->{racScanTnsConf} = $racScanTnsConf;

                my $rmanDbTnsConf = "${dbUniqueName}_rman = \n";
                $rmanDbTnsConf        = $rmanDbTnsConf . "  (DESCRIPTION =\n";
                $rmanDbTnsConf        = $rmanDbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $localIp)(PORT = $port))\n";
                $rmanDbTnsConf        = $rmanDbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SID = $localInsName))\n)\n";
                $out->{rmanDbTnsConf} = $rmanDbTnsConf;
            }

            $out->{lsnrOraConfPath} = $GRID_HOME . '/network/admin/listener.ora';
            $out->{tnsOraConfPath}  = $ORACLE_HOME . '/network/admin/tnsnames.ora';
            if ( not -e $out->{lsnrOraConfPath} ) {
                system(qq{su - $GRID_USER -c "touch '$out->{lsnrOraConfPath}'"});
            }
            if ( not -e $out->{tnsOraConfPath} ) {
                system(qq{su - $ORACLE_USER -c "touch '$out->{tnsOraConfPath}'"});
            }

            my $pwdFileName = "orapw$dbUniqueName.dat";
            my $pwdFilePath = $racInfo->{PASSWORD_FILE};
            $out->{pwdFilePath} = $pwdFilePath;

            if ( not defined($pwdFilePath) or $pwdFilePath eq '' ) {
                $pwdFilePath = $ORACLE_HOME . "/dbs/orapw$localInsName";
            }

            my $curDir = getcwd();
            chmod( 0777, $curDir );
            my $localPwdFilePath = "$curDir/$pwdFileName";
            if ( $pwdFilePath =~ /^\+/ ) {
                system("'$GRID_HOME/bin/asmcmd' pwcopy '$pwdFilePath' '$localPwdFilePath'");
            }
            else {
                copy( $pwdFilePath, $localPwdFilePath );
            }

            if ( not -e $localPwdFilePath ) {
                print("WARN: Copy password file from $pwdFilePath failed.\n");
            }

            $out->{pwdFile} = $pwdFileName;
        }
    }
    else {
        my $ip   = $ENV{MGMT_IP};
        my $port = 1521;

        $out->{allGridNodesInfo}   = [ { ip => $ip } ];
        $out->{otherGridNodesInfo} = [];
        $out->{thisNodesInfo}      = [ { ip => $ip } ];
        $out->{operNodeInfo}       = [ { ip => $ip } ];
        $out->{otherNodeNames}     = '';

        if ( $onlyNodes == 0 ) {
            my $dbInfo = getDBParameters($ORACLE_USER);

            if ( not defined($dbUniqueName) or $dbUniqueName eq '' ) {
                if ( not defined($dbUniqueName) or $dbUniqueName eq '' ) {
                    $dbUniqueName = $dbInfo->{db_unique_name};
                }
            }

            if ( not defined($dbName) or $dbName eq '' ) {
                $dbName = $dbInfo->{db_name};
            }

            my $localInsName = $dbInfo->{instance_name};
            if ( not defined($localInsName) or $localInsName eq '' ) {
                my $oraSid = `su - '$ORACLE_USER' -c "echo \$ORACLE_SID"`;
                $oraSid =~ s/^\s*|\s*$//g;
                $localInsName = $oraSid;
            }

            $out->{dbParameters} = $dbInfo;
            $out->{spfilePath}   = $dbInfo->{spfile};

            my $lsnAddrs = getLsnrAddrs($ORACLE_USER);
            if ( scalar(@$lsnAddrs) > 0 ) {
                my $lsnrInfo = $$lsnAddrs[0];
                $ip   = $lsnrInfo->{host};
                $port = $lsnrInfo->{port};

                my $uniqDbTnsConf = "$dbUniqueName = \n";
                $uniqDbTnsConf = $uniqDbTnsConf . "  (DESCRIPTION =\n";
                $uniqDbTnsConf = $uniqDbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $ip)(PORT = $port))\n";
                if ( $majorVersion >= 10 ) {

                    #Oracle版本大于等于10，增加了UR=A的设定，让tns可以再实例监听处于BLOCKED状态仍然可以进行管理连接
                    $uniqDbTnsConf = $uniqDbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbUniqueName) (UR=A))\n)\n";
                }
                else {
                    $uniqDbTnsConf = $uniqDbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbUniqueName))\n)\n";
                }

                my $dbTnsConf = "$dbName = \n";
                $dbTnsConf = $dbTnsConf . "  (DESCRIPTION =\n";
                $dbTnsConf = $dbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $ip)(PORT = $port))\n";
                $dbTnsConf = $dbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = $dbName))\n)\n";

                my $rmanDbTnsConf = "${dbUniqueName}_rman = \n";
                $rmanDbTnsConf        = $rmanDbTnsConf . "  (DESCRIPTION =\n";
                $rmanDbTnsConf        = $rmanDbTnsConf . "    (ADDRESS = (PROTOCOL = TCP)(HOST = $ip)(PORT = $port))\n";
                $rmanDbTnsConf        = $rmanDbTnsConf . "  (CONNECT_DATA = (SERVER = DEDICATED) (SID = $localInsName))\n)\n";
                $out->{rmanDbTnsConf} = $rmanDbTnsConf;

                $out->{uniqDbTnsConf} = $uniqDbTnsConf;
                $out->{dbTnsConf}     = $dbTnsConf;
            }

            $out->{lsnrOraConfPath} = $ORACLE_HOME . '/network/admin/listener.ora';
            $out->{tnsOraConfPath}  = $ORACLE_HOME . '/network/admin/tnsnames.ora';

            if ( not -e $out->{lsnrOraConfPath} ) {
                system(qq{su - $ORACLE_USER -c "touch '$out->{lsnrOraConfPath}'"});
            }
            if ( not -e $out->{tnsOraConfPath} ) {
                system(qq{su - $ORACLE_USER -c "touch '$out->{tnsOraConfPath}'"});
            }

            my $pwdFileName = "orapw$dbUniqueName.dat";
            my $pwdFilePath = $ORACLE_HOME . "/dbs/orapw$localInsName";
            $out->{pwdFilePath} = $pwdFilePath;
            copy( $pwdFilePath, $pwdFileName );

            if ( not -e $pwdFileName ) {
                print("WARN: Copy password from $pwdFilePath failed.\n");
            }
            $out->{pwdFile} = $pwdFileName;
        }
    }
    if ( $onlyNodes == 0 ) {
        $out->{hostsConfTxt} = AutoExecUtils::getFileContent('/etc/hosts');
    }

    AutoExecUtils::saveOutput($out);

    return 0;
}

exit( main() );
